package com.qys.livesMall.financial.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qys.livesMall.app.user.model.entity.AppUserLevel;
import com.qys.livesMall.app.user.model.entity.H2AppUser;
import com.qys.livesMall.app.user.model.entity.H2AppUserBalance;
import com.qys.livesMall.app.user.service.AppUserLevelService;
import com.qys.livesMall.app.user.service.IH2AppUserBalanceService;
import com.qys.livesMall.app.user.service.IH2AppUserService;
import com.qys.livesMall.common.exception.QysException;
import com.qys.livesMall.common.utils.MessageUtils;
import com.qys.livesMall.financial.mapper.FinancialOfflineMapper;
import com.qys.livesMall.financial.model.dto.sys.FinancialOfflineDetailSaveDTO;
import com.qys.livesMall.financial.model.dto.sys.FinancialOfflinePageDTO;
import com.qys.livesMall.financial.model.dto.sys.FinancialOfflineSaveDTO;
import com.qys.livesMall.financial.model.entity.FinancialOffline;
import com.qys.livesMall.financial.model.entity.FinancialOfflineDetail;
import com.qys.livesMall.financial.model.entity.FinancialOfflineUser;
import com.qys.livesMall.financial.model.vo.app.AppFinancialOfflineDetailVO;
import com.qys.livesMall.financial.model.vo.app.AppFinancialOfflinePageVO;
import com.qys.livesMall.financial.model.vo.sys.FinancialOfflinePageVO;
import com.qys.livesMall.financial.model.vo.sys.FinancialOfflineVO;
import com.qys.livesMall.financial.service.FinancialOfflineDetailService;
import com.qys.livesMall.financial.service.FinancialOfflineService;
import com.qys.livesMall.financial.service.FinancialOfflineUserService;
import com.qys.livesMall.framework.utils.SecurityUtils;
import com.qys.livesMall.framework.view.BaseQuery;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 线下理财 服务实现类
 * </p>
 *
 * @author
 * @since 2023-06-10
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class FinancialOfflineServiceImpl extends ServiceImpl<FinancialOfflineMapper, FinancialOffline> implements FinancialOfflineService {

    private final IH2AppUserService userService;
    private final AppUserLevelService userLevelService;
    private final IH2AppUserBalanceService userBalanceService;
    private final FinancialOfflineUserService offlineUserService;
    private final FinancialOfflineDetailService offlineDetailService;

    /**
     * 分页查询线下理财信息
     *
     * @param pageDTO {@link  FinancialOfflinePageDTO}
     */
    @Override
    public Page<FinancialOfflinePageVO> pageBySys(FinancialOfflinePageDTO pageDTO) {
        Page<FinancialOfflinePageVO> page = new Page<>(pageDTO.getPageNum(), pageDTO.getPageSize());
        page.setRecords(baseMapper.listBySysPage(page, pageDTO));
        return page;
    }

    /**
     * 新增/编辑线下理财信息
     *
     * @param saveDTO {@link  FinancialOfflineSaveDTO}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(FinancialOfflineSaveDTO saveDTO) {
        log.info("管理员操作任务信息,操作人：{}，操作信息：{}", SecurityUtils.getUsername(), saveDTO);

        FinancialOffline offline = new FinancialOffline();
        BeanUtils.copyProperties(saveDTO, offline);
        offline.setDetailCount((byte) saveDTO.getDetailList().size());
        //offline.setIncome(saveDTO.getIncome().divide(new BigDecimal("100"), 4, RoundingMode.DOWN));
        offline.setIncome(saveDTO.getIncome());
        //等级
        AppUserLevel userLevel = userLevelService.getById(saveDTO.getUserLevelId());
        if (null == userLevel) {
            throw new QysException(MessageUtils.message("user.level.null"));
        }
        offline.setUserLevel(userLevel.getName());

        //新增
        if (saveDTO.getId() == null) {
            offline.setCreator(SecurityUtils.getUsername());
            offline.setCreateTime(LocalDateTime.now());
        }
        //编辑
        else {
            //删除明细
            offlineDetailService.remove(Wrappers.<FinancialOfflineDetail>query().eq("offline_id", saveDTO.getId()));
        }
        saveOrUpdate(offline);

        //明细
        offlineDetailService.save(saveDTO.getDetailList(), offline.getId());
    }

    /**
     * 删除线上理财
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long id) {
        FinancialOffline offline = baseMapper.selectById(id);
        if (null == offline) {
            throw new QysException("The information to be deleted was not obtained");
        }
        if (offline.getStatus() == 1) {
            throw new QysException("The current state cannot be deleted");
        }
        baseMapper.deleteById(id);
        //删除明细
        offlineDetailService.remove(Wrappers.<FinancialOfflineDetail>query().eq("offline_id", id));
    }

    /**
     * 上架下架
     *
     * @param id
     */
    @Override
    public void shelves(Long id) {
        FinancialOffline offline = baseMapper.selectById(id);
        if (null == offline) {
            throw new QysException("The information to be shelves was not obtained");
        }
        offline.setStatus((byte) (offline.getStatus().intValue() == 0 ? 1 : 0));
        baseMapper.updateById(offline);
    }

    /**
     * APP-分页查询线下理财信息
     *
     * @param baseQuery {@link  BaseQuery}
     */
    @Override
    public Page<AppFinancialOfflinePageVO> pageByApp(BaseQuery baseQuery) {
        Page<AppFinancialOfflinePageVO> page = new Page<>(baseQuery.getPageNum(), baseQuery.getPageSize());
        List<AppFinancialOfflinePageVO> pageVOList = baseMapper.listByAppPage(page, baseQuery);

        //用户任务信息
        if (CollectionUtils.isNotEmpty(pageVOList)) {
            page.setRecords(setUserFinancialInfo(pageVOList));
        }
        return page;
    }

    /**
     * APP-分页查询理财信息设置用户完成任务信息
     */
    private List<AppFinancialOfflinePageVO> setUserFinancialInfo(List<AppFinancialOfflinePageVO> pageVOList) {
        List<AppFinancialOfflinePageVO> resultVoList = new ArrayList<>(pageVOList.size());

        for (AppFinancialOfflinePageVO vo : pageVOList) {
            //1.查询任务明细
            List<FinancialOfflineDetail> detailList = offlineDetailService.list(Wrappers.<FinancialOfflineDetail>query()
                    .eq("offline_id", vo.getId())
                    .orderByAsc("`sort`")
            );
            if (CollectionUtils.isEmpty(detailList)) {
                continue;
            }

            //1.1转换vo
            List<AppFinancialOfflineDetailVO> detailVOS = BeanUtil.copyToList(detailList, AppFinancialOfflineDetailVO.class);

            //2.用户观看任务信息
            FinancialOfflineUser offlineUser = offlineUserService.getOne(Wrappers.<FinancialOfflineUser>query()
                    .eq("user_id", SecurityUtils.getUserId())
                    .eq("financial_id", vo.getId())
                    .orderBy(true, false, "finish_time is null", "finish_time")
                    .last("LIMIT 1")
            );

            //3.设置任务状态与观看记录信息
            setTaskStatusAndUserWatch(detailVOS, offlineUser, vo);

            //设置明细信息
            vo.setDetailVOS(detailVOS);

            resultVoList.add(vo);
        }
        return resultVoList;
    }

    /**
     * 设置任务状态与用户观看记录信息
     *
     * @param detailList  {@link AppFinancialOfflineDetailVO}
     * @param offlineUser {@link  FinancialOfflineUser}
     * @param vo          {@link AppFinancialOfflinePageVO}
     */
    private void setTaskStatusAndUserWatch(List<AppFinancialOfflineDetailVO> detailList, FinancialOfflineUser offlineUser,
                                           AppFinancialOfflinePageVO vo) {
        //1.用户看过视频
        if (null != offlineUser && offlineUser.getFinishTime() == null) {
            //获取用户看过视频序号
            List<Byte> detailSort = JSONUtil.toList(offlineUser.getFinancialSort(), Byte.class);
            //设置任务明细观看为true
            detailSort.stream().forEach(sort -> detailList.get(sort).setFinish((byte) 1));
            //设置视频任务状态为进行中
            vo.setStatus((byte) 1);
        }
        //2.没看过视频
        else {
            //完成任务
            if (null != offlineUser && !offlineUser.getNextFinancialTime().isBefore(LocalDate.now())) {
                vo.setStatus((byte) 2);
                //将任务设置为已完成
                detailList.stream().forEach(detail -> detail.setFinish((byte) 1));
            }
            //用户没有完成任务 或者 看过已过冷却期
            else {
                vo.setStatus((byte) 0);
            }
        }
    }

    /**
     * 根据id查询任务信息
     *
     * @param id
     */
    @Override
    public FinancialOfflineVO queryById(Long id) {
        FinancialOffline offline = baseMapper.selectById(id);
        if (null == offline) {
            throw new QysException("can not find financial info");
        }

        FinancialOfflineVO vo = new FinancialOfflineVO();
        BeanUtils.copyProperties(offline, vo);

        //明细
        List<FinancialOfflineDetail> detailList = offlineDetailService.list(Wrappers.<FinancialOfflineDetail>query()
                .eq("offline_id", vo.getId())
                .orderByAsc("`sort`"));

        List<FinancialOfflineDetailSaveDTO> saveDTOS = BeanUtil.copyToList(detailList, FinancialOfflineDetailSaveDTO.class);
        vo.setDetailList(saveDTOS);

        return vo;
    }

    /**
     * APP用户理财权限校验
     *
     * @param offlineId 理财id
     */
    @Override
    public void checkPromiseByApp(Long offlineId) {
        FinancialOffline offline = baseMapper.selectById(offlineId);
        if (null == offline) {
            throw new QysException(MessageUtils.message("financial.level.not.match"));
        }

        //等级
        AppUserLevel userLevel = userLevelService.getById(offline.getUserLevelId());
        if (null == userLevel || userLevel.getOfflineFinancialFlag() == 2) {
            throw new QysException(MessageUtils.message("financial.level.not.match"));
        }

        //用户用户
        H2AppUser appUser = userService.getById(SecurityUtils.getUserId());
        if (null == appUser || !Objects.equals(appUser.getUserLevelId(), offline.getUserLevelId())) {
            throw new QysException(MessageUtils.message("financial.level.not.match"));
        }

        //余额
        H2AppUserBalance userBalance = userBalanceService.queryByUserId(SecurityUtils.getUserId());
        if (null == userBalance || userBalance.getBalance().compareTo(offline.getAmountMin()) < 0) {
            throw new QysException(MessageUtils.message("financial.balance.not.match"));
        }
    }
}
